/*****************************************************************************
* File Name: trackpad_custom_gesture.c
*
* Version: 1.0
*
* Description:
* This file contains custom gesture implementation
*
* Note:
* Define DISABLE_TRACKPAD in platform.h to disable trackpad module
*
* Owner: SKUV
*
* Related Document:
* Capsense CSD P4 component datasheet
*
* Hardware Dependency:
* CapSense Gesture component
*
* Code Tested With:
* 1. PSoC Creator 3.1 
* 2. ARM GCC 4.8.4
******************************************************************************
* Copyright (2015), Cypress Semiconductor Corporation.
******************************************************************************
* This software is owned by Cypress Semiconductor Corporation (Cypress) and is
* protected by and subject to worldwide patent protection (United States and
* foreign), United States copyright laws and international treaty provisions.
* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable
* license to copy, use, modify, create derivative works of, and compile the
* Cypress Source Code and derivative works for the sole purpose of creating
* custom software in support of licensee product to be used only in conjunction
* with a Cypress integrated circuit as specified in the applicable agreement.
* Any reproduction, modification, translation, compilation, or representation of
* this software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
* Cypress reserves the right to make changes without further notice to the
* materials described herein. Cypress does not assume any liability arising out
* of the application or use of any product or circuit described herein. Cypress
* does not authorize its products for use as critical components in life-support
* systems where a malfunction or failure may reasonably be expected to result in
* significant injury to the user. The inclusion of Cypress' product in a life-
* support systems application implies that the manufacturer assumes all risk of
* such use and in doing so indemnifies Cypress against all charges. Use may be
* limited by and subject to the applicable Cypress software license agreement.
*****************************************************************************/
#include "trackpad.h"
#include "trackpad_custom_gesture.h"

#if !defined(DISABLE_TRACKPAD) && !defined(TOUCH_TUNER)

extern CSD_Touchpad_POSITION_STRUCT fingerPosition[2];
extern uint32 numberOfFingers;
extern uint32 prevnumberofFingers;

#ifndef DISABLE_CLICK_DETECTION_POINTER_MOVEMENT
static int16 initialFingerPositionX, initialFingerPositionY;
static bool isPointerEnabled = false;
#else
static bool isPointerEnabled = true;
#endif /* DISABLE_CLICK_DETECTION_POINTER_MOVEMENT */

#ifdef DIFF_POINTER_MOVEMENT
static CSD_Touchpad_POSITION_STRUCT prevFingerPosition[2];
#endif /* DIFF_POINTER_MOVEMENT */

/*****************************************************************************
* Function Name: Trackpad_Custom_Gesture_Init()
******************************************************************************
* Summary:
* This function initialises various parameters for the that is required for the 
* custom gestures
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
*
* Note:
* None
*****************************************************************************/
void Trackpad_Custom_Gesture_Init(void)
{
#ifndef DISABLE_CUSTOM_POINTER_MOVEMENT
    Trackpad_Ballasitic_Filter ballasisticFilter = {BALLASITIC_FILTER_ACCELERATION,
                                                    BALLASITIC_FILTER_SPEED_LEVEL,
                                                    BALLASITIC_FILTER_DIVISOR_VALUE,
                                                    BALLASITIC_FILTER_THRESHOLD_X,
                                                    BALLASITIC_FILTER_THRESHOLD_Y};

#endif /* DISABLE_CUSTOM_POINTER_MOVEMENT */
#ifndef DISABLE_CUSTOM_SCROLL_GESTURE
    Tracakpad_Scroll_Gesture gestureConfig = {(TRACKPAD_VERTICAL_SCROLL_UP_GESTURE | TRACKPAD_VERTICAL_SCROLL_DOWN_GESTURE | TRACKPAD_HORIZONTAL_SCROLL_LEFT_GESTURE | TRACKPAD_HORIZONTAL_SCROLL_RIGHT_GESTURE),
                                               SCROLL_VERTICAL_START_BOUNDARY,
                                               SCROLL_VERTICAL_STOP_BOUNDARY,
                                               SCROLL_VERTICAL_DISTANCE,
                                               SCROLL_VERTICAL_TIME_THRESHOLD,
                                               SCROLL_HORIZONTAL_START_BOUNDARY,
                                               SCROLL_HORIZONTAL_STOP_BOUNDARY,
                                               SCROLL_HORIZONTAL_DISTANCE,
                                               SCROLL_HORIZONTAL_TIME_THRESHOLD};


    Trackpad_Scroll_Gesture_Init(gestureConfig);
#endif /* DISABLE_CUSTOM_SCROLL_GESTURE */
#ifndef DISABLE_CUSTOM_POINTER_MOVEMENT
    Trackpad_Ballasitic_Init(ballasisticFilter);
#endif /* DISABLE_CUSTOM_POINTER_MOVEMENT */

#ifndef DISABLE_EDGE_SWIPE_TOP
    /* Configuration for the enabling the only CSD_Touchpad_EDGE_SWIPE_TOP and block the 
     * CSD_Touchpad_EDGE_SWIPE_LEFT, CSD_Touchpad_EDGE_SWIPE_RIGHT and CSD_Touchpad_EDGE_SWIPE_BOTTOM 
     * gesture 
     */
    CSD_Touchpad_gesturesConfig.group1Start = CSD_Touchpad_EDGE_SWIPE_LEFT;
    CSD_Touchpad_gesturesConfig.group1End = CSD_Touchpad_EDGE_SWIPE_RIGHT;
    CSD_Touchpad_gesturesConfig.groupMask &= ~CSD_Touchpad_GROUP1_MASK;

    CSD_Touchpad_gesturesConfig.group2Start = CSD_Touchpad_EDGE_SWIPE_BOTTOM;
    CSD_Touchpad_gesturesConfig.group2End = CSD_Touchpad_EDGE_SWIPE_BOTTOM;
    CSD_Touchpad_gesturesConfig.groupMask &= ~CSD_Touchpad_GROUP2_MASK;

    CSD_Touchpad_TMG_InitGestures(&CSD_Touchpad_gesturesConfig);
#endif /* DISABLE_EDGE_SWIPE_TOP */
}

/*****************************************************************************
* Function Name: Trackpad_Custom_PointerMovement_Calulation()
******************************************************************************
* Summary:
* This function calculates pointer movement and returns report type
*
* Parameters:
* Report *report - Pointer for report structure
* bool *is_pointer_movement - Pointer for is_pointer_movement variable
*
* Return:
* None
*
* Theory:
* Calculates the difference of the current  and previous pointer movement if 
* DIFF_POINTER_MOVEMENT macro is defined else uses the diff from the 
* CSD_Touchpad_GetDiffDoubleCentroidPos api
* 
* Side Effects:
* prevFingerPosition is updated
*
* Note:
* None
*****************************************************************************/
ReportType Trackpad_Custom_PointerMovement_Calulation(Report *report, bool *is_pointer_movement)
{
    ReportType reportType = NO_REPORT;
  
#ifdef DIFF_POINTER_MOVEMENT
    if (isPointerEnabled && ((prevFingerPosition[0].x !=0) || (prevFingerPosition[0].y !=0)))
    {
        if((fingerPosition[0].x != prevFingerPosition[0].x) || (fingerPosition[0].y != prevFingerPosition[0].y))
        {
            report->mouse_report.x = (int8)((int16)fingerPosition[0].x - (int16)prevFingerPosition[0].x);
            report->mouse_report.y = (int8)((int16)fingerPosition[0].y - (int16)prevFingerPosition[0].y);
#ifndef DISABLE_CUSTOM_POINTER_MOVEMENT
            Trackpad_Ballasitic_Pointer(&report->mouse_report.x, &report->mouse_report.y);
#endif /* DISABLE_CUSTOM_POINTER_MOVEMENT */
            reportType |= MOUSE_REPORT;
        }
    }

    if(isPointerEnabled)
    {
        prevFingerPosition[0].x = fingerPosition[0].x;
        prevFingerPosition[0].y = fingerPosition[0].y;
        *is_pointer_movement = true;
    }
#else
    static CSD_Touchpad_DIFF_POSITION_STRUCT diffFingerPositions[2];
    CSD_Touchpad_GetDiffDoubleCentroidPos(diffFingerPositions);
    if ((prevnumberofFingers == 1) && (numberOfFingers == 1))
    {
        if(diffFingerPositions[0].x || diffFingerPositions[1].y)
        {
            report->mouse_report.x = diffFingerPositions[0].x;
            report->mouse_report.y = diffFingerPositions[0].y;
            reportType |= MOUSE_REPORT;
            *is_pointer_movement = true;
        }
    }
#endif /* DIFF_POINTER_MOVEMENT */
    return reportType;
}

/*****************************************************************************
* Function Name: Trackpad_Custom_PointerMovement_Reset()
******************************************************************************
* Summary:
* This function resets the pointer movement parameters
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
*
* Note:
* None
*****************************************************************************/
void Trackpad_Custom_PointerMovement_Reset(void)
{
#ifndef DISABLE_CUSTOM_POINTER_MOVEMENT
        Trackpad_Ballasitic_Reset();
#endif /* DISABLE_CUSTOM_POINTER_MOVEMENT */
        prevFingerPosition[0].x = 0;
        prevFingerPosition[0].y = 0;
}

/*****************************************************************************
* Function Name: Trackpad_Custom_Gesture_Detection()
******************************************************************************
* Summary:
* This function calls the custom gesture algorithm for detection of the custom gesture
*
* Parameters:
* uint8 *gesture_code - Pointer for gesture_code variable
*
* Return:
* None
*
* Theory:
* Region based scroll gesture and Top edge swipe gesture are implemented in this function
* Region based scroll gesture:  Indicative scroll region on the trackpad is shown below
*             _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
*            |                      |  V  |
*            |                      |  E  |
*            |                      |  R  |
*            |                      |  T  |
*            |                      |  I  |
*            |                      |  C  |
*            |                      |  A  |
*            |                      |  L  |   
*            |_ _ _ _ _ _ _  _ _ _ _|     | 
*            |     HORIZONTAL       SCROLL|
*            | _ _ _ _ _ _ _ _ _ _ __ _ _ | 
*
*
* Top edge to Bottom swipe: Indicative gesture on trackpad is shown as below
*             _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
*            |                             |
*            |  Top edge swipe start region|
*            |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _| 
*            |                             |
*            |                             |
*            |     Activation Threshold    |
*            | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | 
*            |                             |
*            |                             |
*            |                             |
*            |                             |
*            |                             |
*            |                             |
*            | _ _ _ _ _ _ _ _ _ _ _ _ _ _ | 
*
*
* Side Effects:
* None
*
* Note:
* None
*****************************************************************************/
void Trackpad_Custom_Gesture_Detection(uint8 *gesture_code)
{
#ifndef DISABLE_CLICK_DETECTION_POINTER_MOVEMENT
    static uint32 pointerTimeStamp;
    int16 diffX, diffY;
#endif /* DISABLE_CLICK_DETECTION_POINTER_MOVEMENT */

#ifndef DISABLE_ZOOM_GESTURE
    static uint8 zoomincount = 0x00;
    static uint8 zoomoutcount = 0x00;
#endif /* DISABLE_ZOOM_GESTURE */

#ifndef DISABLE_CUSTOM_SCROLL_GESTURE
    uint8 scrollGesture;
#endif /* DISABLE_CUSTOM_SCROLL_GESTURE */

#ifndef DISABLE_EDGE_SWIPE_TOP
    static uint32 edgeswipeTimeStamp;
    static bool edgeGesturedetected;
    static bool edgeSwipeactive = false;

    if ((prevnumberofFingers == 0) && (numberOfFingers == ONE_FINGER_DETECTED))
    {
        if (fingerPosition[0].y < EDGE_SWIPE_BOUNDARY)
        {
            edgeSwipeactive = true;
            edgeswipeTimeStamp = Timer_Get_Time_Stamp();
        }
    }
    
    if (edgeSwipeactive && (*gesture_code != CSD_Touchpad_EDGE_SWIPE_TOP))
    {
        *gesture_code = DUMMY_GESTURE;
    }

    if (*gesture_code == CSD_Touchpad_EDGE_SWIPE_TOP)
    {
        edgeGesturedetected= true;
        edgeswipeTimeStamp = Timer_Get_Time_Stamp();
    }

    if (!edgeGesturedetected)
    {
        if (((Timer_Time_Elapsed(edgeswipeTimeStamp, EDGE_SWIPE_TIMEOUT)) || \
                                                            (numberOfFingers != ONE_FINGER_DETECTED) \
                                                            || (fingerPosition[0].y > EDGE_SWIPE_ACTIVATION_THRESHOLD)))
        {
               edgeSwipeactive = false;
        }
    }
    else
    {
        if (Timer_Time_Elapsed(edgeswipeTimeStamp, EDGE_SWIPE_DETECTED_TIMEOUT) || \
                                                (numberOfFingers != ONE_FINGER_DETECTED))
        {
            edgeSwipeactive = false;
            edgeGesturedetected= false;
        }
    }
#endif /* DISABLE_EDGE_SWIPE_TOP */

#ifndef DISABLE_CUSTOM_SCROLL_GESTURE
    /* Detection of scroll gesture from the library */
    scrollGesture = Trackpad_Scroll_Gesture_Dection(numberOfFingers,fingerPosition[0].x, fingerPosition[0].y);
    if(scrollGesture & TRACKPAD_VERTICAL_SCROLL_UP_GESTURE)
    {
        *gesture_code = EDGE_VERTICAL_SCROLL_NORTH;
    }
    else if(scrollGesture & TRACKPAD_VERTICAL_SCROLL_DOWN_GESTURE)
    {
        *gesture_code = EDGE_VERTICAL_SCROLL_SOUTH;
    }
    else if(scrollGesture & TRACKPAD_HORIZONTAL_SCROLL_LEFT_GESTURE)
    {
        *gesture_code = EDGE_HORIZONTAL_SCROLL_EAST;
    }
    else if(scrollGesture & TRACKPAD_HORIZONTAL_SCROLL_RIGHT_GESTURE)
    {
        *gesture_code = EDGE_HORIZONTAL_SCROLL_WEST;
    }
    else if(Trackpad_IsScrollDetectionInProgress())
    {
        *gesture_code = DUMMY_GESTURE;
    }
#endif /* DISABLE_CUSTOM_SCROLL_GESTURE */

#ifndef DISABLE_ZOOM_GESTURE
    /* Decodes the zoom gesture and sends after the threshold is reached */
    if(*gesture_code == CSD_Touchpad_ZOOM_OUT)
	{
        zoomoutcount++;
	    if (zoomoutcount == ZOOM_OUT_COUNT_THRESHOLD)
		{
			*gesture_code = CSD_Touchpad_ZOOM_OUT;
            zoomoutcount = 0x00;
		}
		else
		{
			*gesture_code = DUMMY_GESTURE;
		}	
	}

    if(*gesture_code == CSD_Touchpad_ZOOM_IN)
	{
        zoomincount++;
	    if (zoomincount == ZOOM_IN_COUNT_THRESHOLD)
		{
			*gesture_code = CSD_Touchpad_ZOOM_IN;
            zoomincount = 0x00;
		}
		else
		{
			*gesture_code = DUMMY_GESTURE;
		}	
	}
    
    if(numberOfFingers != 2)
    {
        zoomincount = 0x00;
        zoomoutcount = 0x00;
    }
#endif /* DISABLE_ZOOM_GESTURE */

#ifndef DISABLE_CLICK_DETECTION_POINTER_MOVEMENT
    /* Below is the code that is used for blocking pointer movement 
     * when click detection is in progress 
     */
    if ((prevnumberofFingers == 0) && (numberOfFingers == 1))
    {
        pointerTimeStamp = Timer_Get_Time_Stamp();
        initialFingerPositionX = fingerPosition[0].x;
        initialFingerPositionY = fingerPosition[0].y;
    }
    else if((numberOfFingers == 1) && !isPointerEnabled)    
    {
        diffX = fingerPosition[0].x - initialFingerPositionX;
        diffY = fingerPosition[0].y - initialFingerPositionY;
        
        if(diffX < 0)
        {
            diffX = -diffX;
        }
        
        if(diffY < 0)
        {
            diffY = -diffY;
        }
        
        if(Timer_Time_Elapsed(pointerTimeStamp, CLICK_DETECTION_TIMEOUT) || \
                        ((diffX  >= CLICK_X_RADIUS) || (diffY  >= CLICK_Y_RADIUS)))
        {
            isPointerEnabled = true;
        }
    }
    else if((numberOfFingers != 1))
    {
        isPointerEnabled = false;
    }
#endif /* DISABLE_CLICK_DETECTION_POINTER_MOVEMENT */
}

#endif /* !defined(DISABLE_TRACKPAD) && !defined(TOUCH_TUNER) */
